<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
    <title>Magnet Demo</title>
    <style>
      body {
        margin: 0;
      }
      * { font-size: 3vmin; }
      #lines, #paper {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
      }
      #paper {
        display: flex;
        flex-flow: column;
      }
      #tool {
        position: absolute;
        top: 0;
        left: 0;
        padding: 1vmin;
        padding-top: 3vmin;
        background-color: #999;
        font-family: monospace;
        line-height: 150%;
        display: inline-block;
        z-index: 0;
        cursor: move;
        user-select: none;
      }
      #tool >* {
        background-color: #eee;
        white-space: nowrap;
      }
      #add {
        border: .1vmin solid #666;
      }
      #container {
        flex: 2 2;
      }
      input, button {
        outline: none;
        border: .1vmin solid #666;
        font-family: monospace;
        color: #333;
      }
      input[type=checkbox] {
        width: 3vmin;
        height: 3vmin;
      }
      button { background-color: #eee; }
      button:active { transform: translate(.1vmin, .1vmin); }
      #lines {
        z-index: 1;
        pointer-events: none;
      }
      #lines >* {
        position: absolute;
        width: 1px;
        height: 1px;
        background-color: #999;
        opacity: 0;
      }
      #lines >.show { opacity: .5; }
      #lines .vert {
        transform: translateX(-50%);
        height: 100%;
      }
      #lines .hori {
        transform: translateY(-50%);
        width: 100%;
      }
      .block {
        position: absolute;
        overflow: auto;
      }
      .block.focused {
        box-shadow: 0 0 3vmin 1vmin #fc0;
      }
      .block input {
        position: absolute;
        top: 0;
        right: 0;
      }
    </style>
    <script src="../magnet.min.js"></script>
    <script>
      let NEAR_DISTANCE = 15;
      const magnet = new Magnet();
      magnet.setAllowDrag(false);

      window.addEventListener('load', () => {
        let domContainer = document.getElementById('container');
        let domMask = document.getElementById('lines');
        let domHoriMagnet = domMask.querySelector('.hori');
        let domVertMagnet = domMask.querySelector('.vert');

        // start/end of magnet attract status
        magnet.on('magnetstart', () => {
          console.log('magnetstart');
        }).on('magnetend', () => {
          console.log('magnetend');
          domHoriMagnet.classList.remove('show');
          domVertMagnet.classList.remove('show');
        });

        // show/hide horizon/vertical edge line
        magnet.on('magnetchange', (e) => {
          let result = e.detail;
          console.log('magnetchange', result);
          let resultX = result.x;
          let resultY = result.y;
          domHoriMagnet.classList.remove('show');
          domVertMagnet.classList.remove('show');
          if (resultX) {
            domVertMagnet.style.left = (resultX.position+'px');
            domVertMagnet.classList.add('show');
          }
          if (resultY) {
            domHoriMagnet.style.top = (resultY.position+'px');
            domHoriMagnet.classList.add('show');
          }
        });

        // generate block
        function genBlock() {
          let rootWidth = window.innerWidth;
          let rootHeight = window.innerHeight;
          let width = Math.max(30, parseInt(Math.random()*rootWidth/2));
          let height = Math.max(30, parseInt(Math.random()*rootHeight/2));
          let block = document.createElement('span');
          let checkbox = document.createElement('input');
          block.style.width = (width+'px');
          block.style.height = (height+'px');
          block.style.top = (parseInt(Math.random()*(window.innerHeight-height))+'px');
          block.style.left = (parseInt(Math.random()*(window.innerWidth-width))+'px');
          block.style.backgroundColor = ('#'+[1, 2, 3].map(() => ('0'+parseInt(100+Math.random()*155).toString(16)).slice(-2)).join(''));
          block.style.opacity = (0.25+Math.random()*0.75);
          block.classList.add('block');

          checkbox.setAttribute('type', 'checkbox');
          checkbox.setAttribute('checked', '');
          checkbox.addEventListener('mousedown', (evt) => evt.stopPropagation());
          checkbox.addEventListener('change', function() {
            let block = this.parentNode;
            if (this.checked) {
              block.style.resize = 'none';
              magnet.add(block);
            } else {
              block.style.resize = 'both';
              magnet.remove(block);
              block.classList.remove('focused');
            }
          });
          block.addEventListener('mousedown', function(e) {
            this.style.zIndex = 10;
          });
          block.addEventListener('click', function() {
            this.style.zIndex = 1;
            domContainer.appendChild(this);
            if (checkbox.checked) {
              Array.prototype.forEach.call(domContainer.querySelectorAll('.block.focused'), (dom) => {
                dom.classList.remove('focused');
              });
              this.classList.add('focused');
            }
          });
          block.addEventListener('dblclick', function() {
            let checkbox = this.querySelector('input[type=checkbox]');
            checkbox.checked = !checkbox.checked;
            if (checkbox.checked) {
              magnet.add(this);
            } else {
              magnet.remove(this);
            }
          });
          ['attract', 'unattract', 'attracted', 'unattracted'].forEach((type) => {
            block.addEventListener(type, function(e) {
              console.log(type, e);
            });
          });

          block.appendChild(checkbox);
          domContainer.appendChild(block);
          magnet.add(block);
          return block;
        }
        
        const domTool = ((domTool) => {
          // movable tool box
          const onStart = (evt) => {
            evt.preventDefault();
            const { clientX: x, clientY: y } = (((evt.touches||[])[0])||evt);
            const ox = (x-domTool.offsetLeft);
            const oy = (y-domTool.offsetTop);
            const onMove = (e) => {
              const { clientX: x, clientY: y } = (((e.touches||[])[0])||e);
              domTool.style.top = `${y-oy}px`;
              domTool.style.left = `${x-ox}px`;
            };
            const onEnd = () => {
              document.removeEventListener('touchmove', onMove);
              document.removeEventListener('mousemove', onMove);
              document.removeEventListener('touchend', onEnd);
              document.removeEventListener('mouseup', onEnd);
              domTool.style.zIndex = '';
            };
            domTool.style.zIndex = 1000;
            document.addEventListener('touchmove', onMove);
            document.addEventListener('mousemove', onMove);
            document.addEventListener('touchend', onEnd);
            document.addEventListener('mouseup', onEnd);
          };
          domTool.addEventListener('touchstart', onStart);
          domTool.addEventListener('mousedown', onStart);
          Array.prototype.forEach.call(domTool.children, (dom) => {
            const onStart = (evt) => evt.stopPropagation();
            dom.addEventListener('touchstart', onStart);
            dom.addEventListener('mousedown', onStart);
          });

          // add one block
          document.getElementById('add').onclick = () => magnet.add(genBlock());

          // distance
          document.getElementById('dist').onchange = () => magnet.distance(NEAR_DISTANCE = this.value);
          magnet.distance(document.getElementById('dist').value = NEAR_DISTANCE);

          // enable/disable stay in parent
          document.getElementById('parentInner').onchange = function() {
            magnet.setStayInParent(this.checked);
          };
          document.getElementById('parentInner').checked = magnet.getStayInParent();

          // enable/disable align parent middle
          document.getElementById('parentMiddle').onchange = function() {
            magnet.setAlignParentCenter(this.checked);
          };
          document.getElementById('parentMiddle').checked = magnet.getAlignParentCenter();

          // enable/disable align outside
          document.getElementById('outside').onchange = function() {
            magnet.setAlignOuter(this.checked);
          };
          document.getElementById('outside').checked = magnet.getAlignOuter();

          // enable/disable align inside
          document.getElementById('inside').onchange = function() {
            magnet.setAlignInner(this.checked);
          };
          document.getElementById('inside').checked = magnet.getAlignInner();

          // enable/disable align middle
          document.getElementById('middle').onchange = function() {
            magnet.setAlignCenter(this.checked);
          };
          document.getElementById('middle').checked = magnet.getAlignCenter();

          document.getElementById('allowDrag').onchange = function() {
            magnet.setAllowDrag(this.checked);
          };
          document.getElementById('allowDrag').checked = magnet.getAllowDrag();

          return domTool;
        })(document.getElementById('tool'));

        // init blocks
        for (let bInx=(2+parseInt(Math.random()*3)); 0<bInx; bInx--) {
          genBlock();
        }

        // magnet.attractable(true);
        // magnet.allowCtrlKey(true);
        document.addEventListener('keydown', function(evt) {
          const blocks = Array.prototype.slice.call(domContainer.querySelectorAll('.block.focused'));
          if (!blocks.length) {
            return;
          }
          const unit = parseInt(document.getElementById('unit').value);
          let convertRect = (rect) => rect;
          switch (evt.which) {
            case 65:
            case 100:
            case 37: // left
            convertRect = ({ top, right, bottom, left, width, height }) => ({
              top, bottom, width, height,
              right: (right-unit),
              left: (left-unit)
            });
            break;

            case 87:
            case 104:
            case 38: // top
            convertRect = ({ top, right, bottom, left, width, height }) => ({
              right, left, width, height,
              top: (top-unit),
              bottom: (bottom-unit)
            });
            break;

            case 68:
            case 102:
            case 39: // right
            convertRect = ({ top, right, bottom, left, width, height }) => ({
              top, bottom, width, height,
              right: (right+unit),
              left: (left+unit)
            });
            break;

            case 83:
            case 98:
            case 40: // bottom
            convertRect = ({ top, right, bottom, left, width, height }) => ({
              right, left, width, height,
              top: (top+unit),
              bottom: (bottom+unit)
            });
            break;
          }
          blocks.forEach((dom) => {
            const rect = convertRect(dom.getBoundingClientRect());
            magnet.handle(dom, rect);
          });
        });
      });
    </script>
  </head>
  <body>
    <div id="lines">
      <span class="vert"></span>
      <span class="hori"></span>
    </div>
    <div id="paper">
      <div id="tool">
        <div id="add">Add Block</div>
        <div class="item">Arrow Unit: <input id="unit" type="number" min="1" max="50" value="20" /></div>
        <div class="item">Distance: <input id="dist" type="number" min="0" max="20" /></div>
        <div class="item"><input id="parentInner" type="checkbox" /><label for="parentInner">Fix in parent</label></div>
        <div class="item"><input id="parentMiddle" type="checkbox" /><label for="parentMiddle">Align Parent Middle</label></div>
        <div class="item"><input id="outside" type="checkbox" /><label for="outside">Align Outside</label></div>
        <div class="item"><input id="inside" type="checkbox" /><label for="inside">Align Inside</label></div>
        <div class="item"><input id="middle" type="checkbox" /><label for="middle">Align Middle</label></div>
        <div class="item"><input id="allowDrag" type="checkbox" /><label for="allowDrag">Allow Drag</label></div>
      </div>
      <div id="container"></div>
    </div>
  </body>
</html>